package com.lin.spring;



import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName MySpring
 * @Description
 * @Author lin
 * @Date 2022/4/4 下午4:08
 * @Version V1.0
 */

public class MySpring {
    // 启动配置类
    private Class confogClass;
    // beanDefinition的map
    private ConcurrentHashMap<String,BeanDefinition> beanDefinitionConcurrentHashMap = new ConcurrentHashMap<>();
    // 单例bean的map
    private ConcurrentHashMap<String,Object> singletonObjects = new ConcurrentHashMap<>();
    // 实现了beanPostProcessorList的bean
    private ArrayList<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    // 初始化扫描配置类,将扫描到的bean放在beanDefinition Map中
    // 后续创建bean根据beanDefinition
    public MySpring(Class confogClass) {
        this.confogClass = confogClass;
        // 扫描
        if(confogClass.isAnnotationPresent(ComponentScan.class)){
            // 扫描类是否有ComponentScan注解
            ComponentScan annotation = (ComponentScan)confogClass.getAnnotation(ComponentScan.class);
            // 获取注解值，得到扫描路径
            String path = annotation.value();
            path = path.replace(".","/");
            // System.out.println("扫描路径："+path);
            // 获取相对路径
            ClassLoader classLoader = MySpring.class.getClassLoader();
            URL resource = classLoader.getResource(path);
            // System.out.println(resource);
            assert resource != null;
            File file = new File(resource.getFile());
            // System.out.println("is dir "+file.isDirectory());
            if(file.isDirectory()){
                File[] files = file.listFiles();
                assert files != null;
                for (File f : files){
                    String absolutePath = f.getAbsolutePath();
                    // System.out.println(absolutePath);
                    // 只对class文件进行处理
                    if(absolutePath.endsWith("class")){
                        String classLoaderPath = absolutePath.substring(absolutePath.indexOf(path),absolutePath.indexOf(".class"));
                        classLoaderPath = classLoaderPath.replace("/",".");
                        // System.out.println(classLoaderPath);
                        try {
                            // bean
                            Class<?> clazz = classLoader.loadClass(classLoaderPath);
                            BeanDefinition beanDefinition = new BeanDefinition();
                            // 只处理@Component bean
                            if(clazz.isAnnotationPresent(Component.class)){
                                // 处理成beanDefinition
                                String beanName = clazz.getAnnotation(Component.class).value();
                                // 如果beanname没有赋值，遵循bean的命名规则
                                if(StringUtils.isEmpty(beanName)){
                                    beanName = Introspector.decapitalize(clazz.getSimpleName());
                                }
                                beanDefinition.setType(clazz);
                                if(clazz.isAnnotationPresent(Scope.class)){
                                    String scope = clazz.getAnnotation(Scope.class).value();
                                    beanDefinition.setScop(scope);
                                }else{
                                    // 默认创建单例bean
                                    beanDefinition.setScop("singleton");
                                }
                                beanDefinitionConcurrentHashMap.put(beanName,beanDefinition);

                                // beanPostProcessorList
                                if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                                    BeanPostProcessor instance = (BeanPostProcessor) clazz.newInstance();
                                    beanPostProcessorList.add(instance);
                                }

                            }
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InstantiationException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }else{
                throw new RuntimeException("路径不是一个文件夹");
            }
        }else{
            throw new RuntimeException("此类不是一个配置类");
        }

        // 单例bean可以直接创建
        for (String beanName : beanDefinitionConcurrentHashMap.keySet()) {
            BeanDefinition definition = beanDefinitionConcurrentHashMap.get(beanName);
            if("singleton".equals(definition.getScop())){
                Object bean = createBean(beanName, definition);
                singletonObjects.put(beanName,bean);
            }

        }
    }

    private Object createBean(String beanName, BeanDefinition definition) {
        Class clazz = definition.getType();
        Object bean = null;
        try {
            bean = clazz.newInstance();
            // 依赖注入
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                // 只对加了Autowired的属性进行赋值  通过反射
                if (field.isAnnotationPresent(Autowired.class)) {
                    field.setAccessible(true);
                    // 根据名称
                    field.set(bean,getBean(field.getName()));
                }
            }

            // BeanNameAware回调，当前bean的名称
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setName(beanName);
            }
            // 初始化之前
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                bean = beanPostProcessor.postProcessBeforeInitialization(beanName, bean);
            }

            // 初始化
            if (bean instanceof InitializingBean) {
                ((InitializingBean)bean).afterPropertiesSet();
            }
            // 初始化之后
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                bean = beanPostProcessor.postProcessAfterInitialization(beanName, bean);
            }

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return bean;
    }

    public Object getBean(String beanName) {
        BeanDefinition beanDefinition = beanDefinitionConcurrentHashMap.get(beanName);
        if(beanDefinition != null){
            // 单例bena先从map获取，获取不到再创建+创建之后缓存；其余bean直接创建
            if("singleton".equals(beanDefinition.getScop())){
                Object bean = singletonObjects.get(beanName);
                if(bean == null){
                    Object bean1 = createBean(beanName, beanDefinition);
                    singletonObjects.put(beanName,bean1);
                    return bean1;
                }
                return bean;
            }else{
                return createBean(beanName,beanDefinition);
            }
        }else{
            throw new RuntimeException("bean name不存在！");
        }
    }
}
